using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;

namespace WINPE_TOOLBOX
{
    public static class CommandUtils
    {
        // 获取系统默认编码
        private static Encoding GetSystemEncoding()
        {
            var codePageEncodings = new Dictionary<string, Encoding>
            {
                { "65001", Encoding.UTF8 },
                { "936", Encoding.GetEncoding("GBK") },
                { "932", Encoding.GetEncoding("Shift_JIS") },
                { "949", Encoding.GetEncoding("KS_C_5601-1987") },
                { "950", Encoding.GetEncoding("Big5") },
                { "1200", Encoding.Unicode },
                { "1201", Encoding.BigEndianUnicode },
                { "1250", Encoding.GetEncoding("Windows-1250") },
                { "1251", Encoding.GetEncoding("Windows-1251") },
                { "1252", Encoding.GetEncoding("Windows-1252") }
            };

            try
            {
                var output = RunCmdSync("chcp");
                var match = System.Text.RegularExpressions.Regex.Match(output, @":\s+(\d+)");
                if (match.Success && codePageEncodings.ContainsKey(match.Groups[1].Value))
                {
                    return codePageEncodings[match.Groups[1].Value];
                }
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e);
            }

            return Encoding.Default;
        }

        // 同步执行命令行
        public static string RunCmdSync(string cmd)
        {
            var encoding = GetSystemEncoding();
            var processInfo = new ProcessStartInfo("cmd.exe", "/c " + cmd)
            {
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true,
                StandardOutputEncoding = encoding
            };

            using (var process = Process.Start(processInfo))
            {
                using (var reader = process.StandardOutput)
                {
                    return reader.ReadToEnd();
                }
            }
        }

        // 异步执行命令行，并通过回调返回结果
        public static void RunCmd(string cmd, Action<string> returnStr, Action<int> end)
        {
            var encoding = GetSystemEncoding();
            var processInfo = new ProcessStartInfo("cmd.exe", "/c " + cmd)
            {
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true,
                StandardOutputEncoding = encoding,
                StandardErrorEncoding = encoding
            };

            var process = new Process { StartInfo = processInfo };

            process.OutputDataReceived += (sender, args) =>
            {
                if (args.Data != null)
                {
                    returnStr(args.Data);
                }
            };

            process.ErrorDataReceived += (sender, args) =>
            {
                if (args.Data != null)
                {
                    Console.Error.WriteLine(args.Data);
                }
            };

            process.Exited += (sender, args) =>
            {
                end(process.ExitCode);
                process.Dispose();
            };

            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
        }

        // 异步执行命令行，并通过 Task 返回结果
        public static Task<string> RunCmdAsync(string cmd)
        {
            return Task.Run(() =>
            {
                var tcs = new TaskCompletionSource<string>();
                var returnStr = new StringBuilder();

                RunCmd(cmd, 
                    data => returnStr.AppendLine(data), 
                    code =>
                    {
                        if (code == 0)
                        {
                            tcs.SetResult(returnStr.ToString());
                        }
                        else
                        {
                            tcs.SetException(new Exception($"命令执行失败：{cmd}, 错误码: {code}"));
                        }
                    });

                return tcs.Task;
            });
        }
    }
}
